/*
 * Copyright 2021 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "powerwindow.h"
#include "enginedevice.h"
#include "xatom-helper.h"
#include "qdesktopwidget.h"

#include <QApplication>
#include <QTimer>
#include <KWindowEffects>

#include "ukuistylehelper/ukuistylehelper.h"
#include "windowmanager/windowmanager.h"

#define PANEL_DBUS_SERVICE "com.ukui.panel.desktop"
#define PANEL_DBUS_PATH "/"
#define PANEL_DBUS_INTERFACE "com.ukui.panel.desktop"
#define UKUI_PANEL_SETTING "org.ukui.panel.settings"

#define ORG_UKUI_STYLE "org.ukui.style"
#define POWER_MANAGER_SETTINGS "org.ukui.power-manager"
#define STYLE_NAME "styleName"
#define SYSTEM_FONT_SIZE "systemFontSize"

#define DBUS_NAME "org.ukui.SettingsDaemon"
#define DBUS_PATH "/org/ukui/SettingsDaemon/wayland"
#define MARGIN 4

#define TRANSPARENCY_SETTINGS "org.ukui.control-center.personalise"
#define TRANSPARENCY_KEY "transparency"

#define POWER_POLICY_AC "powerPolicyAc"
#define POWER_POLICY_BATTERY "powerPolicyBattery"



powerwindow::powerwindow(QWidget *parent) : QWidget(parent)
{
    qDebug() << " notification  init  start";
    QTimer::singleShot(1000, this, [=] {
        m_notifyInterface = new QDBusInterface(
            "org.freedesktop.Notifications",
            "/org/freedesktop/Notifications",
            "org.freedesktop.Notifications",
            QDBusConnection::sessionBus());
    });
    qDebug() << " notification  init  end";

    //    QDBusConnection::sessionBus().connect(
    //        QString(), "/", "org.ukui.upower", "LowBatteryState", this, SLOT(lowBatteryNotify()));
    //    QDBusConnection::sessionBus().connect(
    //        QString(), "/", "org.ukui.upower", "VeryLowBatteryState", this, SLOT(criticalBatteryNotify()));
    //        qDebug()<<"upower init";
    //    QDBusConnection::sessionBus().connect(
    //        QString(), "/", "org.ukui.upower", "PowerState", this, SLOT(chargeNotify(bool)));

    qDebug() << "energy divice init start";
    ed = EngineDevice::getInstance();
    qDebug() << "energy divice init end";
    //    connect(ed, SIGNAL(engine_signal_fullycharge(DEV)), this, SLOT(full_charge_notify(DEV)));

    setWindowProperty(); //设置窗口属性
    initUI();            //初始化UI
    initgsetting();
    //    set_window_position(); //设置出现在屏幕的位置以及大小
    watchTranspartency();
#if 0
    //监听屏幕改变的信号
    connect(QApplication::desktop(), &QDesktopWidget::resized, this, [=]() {
        QTimer::singleShot(1000, this, [=]() { set_window_position(); });
    });
    connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged, this, [=]() { set_window_position(); });
    connect(QApplication::desktop(), &QDesktopWidget::primaryScreenChanged, this, [=]() { set_window_position(); });
#endif
    installEventFilter(this);
}

powerwindow::~powerwindow()
{
    if (nullptr != transparency_gsettings) {
        delete transparency_gsettings;
        transparency_gsettings = nullptr;
    }
    if (nullptr != percentageLabel) {
        delete percentageLabel;
        percentageLabel = nullptr;
    }
}

void powerwindow::setWindowProperty()
{
    //设置任务栏无显示
    setWindowOpacity(1);
    setAttribute(Qt::WA_TranslucentBackground); //设置窗口背景透明
    setProperty("useSystemStyleBlur", true);    //设置毛玻璃效果
    setProperty("useStyleWindowManager", false);
//    this->setFixedSize(360, 300);
}

void powerwindow::initUI()
{
    KWindowEffects::enableBlurBehind(this->winId(), true);

    // 添加窗管协议
    MotifWmHints hints;
    hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
    hints.functions = MWM_FUNC_ALL;
    hints.decorations = MWM_DECOR_BORDER;
    XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints);

    m_pmainlayout = new QVBoxLayout(this);
    m_firstlayout = new QHBoxLayout(this);
    m_toplayout = new QHBoxLayout(this);
    lastlayout = new QHBoxLayout(this);
    m_statelayout = new QHBoxLayout(this);

    m_firstwidget = new QWidget(this);
    m_topwidget = new QWidget(this);
    lastWidget = new QWidget(this);
    m_statewidget = new QWidget(this);

    iconButton = new BatteryIcon(this);

    percentageLabel = new PercentageLabel();

    powerStateLabel = new QLabel(this);
    powerStateLabel->setText(tr("Charging"));
    powerStateLabel->setVisible(false);

    powerTimeToEmpty = new QLabel(this);
    powerTimeToEmpty->setVisible(true);

    m_segmentationLine_1 = new Divider(this);
    m_segmentationLine_2 = new Divider(this);

    m_StateSlider = new StateSlider(this);
    connect(m_StateSlider, &StateSlider::valueChanged, this, &powerwindow::sliderValueChanged);

    m_enduranceIconButtun = new QToolButton(this);
    m_enduranceIconButtun->setIconSize(QSize(16, 16));
    m_enduranceIconButtun->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    m_enduranceIconButtun->setProperty("useIconHighlightEffect", 0x2);
    m_enduranceIconButtun->setStyle(new CustomStyle);
    QIcon icon1 = QIcon::fromTheme("ukui-eco-symbolic");
    m_enduranceIconButtun->setIcon(icon1);

    m_enduranceIconButtun->setText(tr("Endurance"));

    m_performanceIconButtun = new QToolButton(this);
    m_performanceIconButtun->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    m_performanceIconButtun->setProperty("useIconHighlightEffect", 0x2);
    m_performanceIconButtun->setStyle(new CustomStyle);
    QIcon icon2 = QIcon::fromTheme("ukui-performance-symbolic");
    m_performanceIconButtun->setIcon(icon2);
    m_performanceIconButtun->setText(tr("Performance"));

    get_power_list();

    this->setFixedSize(420, 259 + deviceNum * 48);

    //电源设置按钮
    settingLabel = new KyLable(this);
    settingLabel->setText(tr("PowerSettings"));

    toplabel = new QLabel(this);
    toplabel->setText(tr("PowerMode"));
    //    toplabel->setObjectName("");
    m_toplayout->setContentsMargins(24, 0, 24, 0);
    m_toplayout->setSpacing(0);
    m_toplayout->addWidget(toplabel);
    m_toplayout->addItem(new QSpacerItem(10, 2));
    m_topwidget->setLayout(m_toplayout);

    //第一行布局
    m_firstlayout->setContentsMargins(18, 0, 24, 0);
    m_firstlayout->setSpacing(0);
    m_firstlayout->addWidget(iconButton, 0, Qt::AlignLeft | Qt::AlignCenter);
    // m_firstlayout->addStretch();
    m_firstlayout->addWidget(percentageLabel, 0, Qt::AlignLeft | Qt::AlignCenter);
     m_firstlayout->addStretch();
//    m_firstlayout->addItem(new QSpacerItem(180, 5, QSizePolicy::Expanding, QSizePolicy::Minimum));
    m_firstlayout->addWidget(powerTimeToEmpty, 0, Qt::AlignRight | Qt::AlignCenter);
    m_firstlayout->addWidget(powerStateLabel, 0, Qt::AlignRight | Qt::AlignCenter);
//    m_firstlayout->addStretch();

    m_firstwidget->setLayout(m_firstlayout);

    //滑动条下方标识布局
    m_statelayout->setContentsMargins(18, 0, 8, 0);
    m_statelayout->setSpacing(0);
    m_statelayout->addWidget(m_enduranceIconButtun, 0, Qt::AlignLeft | Qt::AlignCenter);
//    m_statelayout->addItem(new QSpacerItem(280, 2, QSizePolicy::Expanding, QSizePolicy::Minimum));
    m_statelayout->addStretch();
    m_statelayout->addWidget(m_performanceIconButtun, 0, Qt::AlignRight);
    m_statewidget->setLayout(m_statelayout);

    //电源设置按钮布局
    lastlayout->setContentsMargins(24, 0, 24, 0);
    lastlayout->setSpacing(0);
    lastlayout->addWidget(settingLabel);
//    lastlayout->addItem(new QSpacerItem(300, 2));
    lastlayout->addStretch();
    lastWidget->setLayout(lastlayout);
    settingLabel->setCursor(Qt::PointingHandCursor);

    //总体布局
    m_pmainlayout->setContentsMargins(0, 0, 0, 0);
    m_pmainlayout->setSpacing(0);
    m_pmainlayout->addWidget(m_topwidget);
    m_pmainlayout->addWidget(m_segmentationLine_1);
    m_pmainlayout->addSpacing(14);
    m_pmainlayout->addWidget(m_firstwidget);
    m_pmainlayout->addSpacing(0);
    m_pmainlayout->addWidget(m_StateSlider, 0, Qt::AlignCenter);
    m_pmainlayout->addSpacing(0);
    m_pmainlayout->addWidget(m_statewidget);
    m_pmainlayout->addWidget(m_segmentationLine_2);
    m_pmainlayout->addWidget(lastWidget);
    this->setLayout(m_pmainlayout);
}

void powerwindow::initgsetting()
{
    const QByteArray styleId(ORG_UKUI_STYLE);
    if (QGSettings::isSchemaInstalled(styleId)) {
        QGSettings *styleSettings = new QGSettings(styleId);
        connect(styleSettings, &QGSettings::changed, this, [=](const QString &key) {
            if (key == SYSTEM_FONT_SIZE) {
                m_sysFontSize = styleSettings->get(SYSTEM_FONT_SIZE).toInt();
                get_power_list();
            }
        });
        m_sysFontSize = styleSettings->get(SYSTEM_FONT_SIZE).toInt();
    }

    const QByteArray powerId(POWER_MANAGER_SETTINGS);
    m_PowerManagerGsettings = new QGSettings(powerId);
    qDebug() << "gsettings  init";
    connect(m_PowerManagerGsettings, &QGSettings::changed, this, [=](const QString &key) {
        if (key == POWER_POLICY_AC || key == POWER_POLICY_BATTERY) {
            qDebug() << "m_PowerManagerGsettings changed !";
            setSliderValue();
        }
    });
}

void powerwindow::get_power_list()
{
    int size;
    size = ed->devices.size();
    for (int i = 0; i < size; i++) {
        DEVICE *dv;
        dv = ed->devices.at(i);

        //通过提示信息，新建widget
        if (dv->m_dev.kind == UP_DEVICE_KIND_LINE_POWER) {
            continue;
        }

        if (dv->m_dev.kind == UP_DEVICE_KIND_BATTERY) {
            percentageLabel->setText(QString("%1%").arg(dv->m_dev.Percentage));

            powerStateLabel->setVisible(true);
            powerTimeToEmpty->setVisible(false);
        }

        connect(ed, &EngineDevice::engine_signal_Battery_State, this, &powerwindow::onBatteryChanged);
        continue;
    }
}

void powerwindow::batteryChange(int dev)
{
    if (dev == 4 || dev == 1 || dev == 5) {
        powerStateLabel->setVisible(true);
        powerTimeToEmpty->setVisible(false);
        toplabel->setText(tr("PowerMode"));
    } else {
        powerStateLabel->setVisible(false);
        powerTimeToEmpty->setVisible(true);
        toplabel->setText(tr("BatteryMode"));
    }
}

void powerwindow::onBatteryChanged(QStringList args)
{
    //    qDebug()<<"电脑电池电量与状态："<<args;
    settings = new QGSettings(GPM_SETTINGS_SCHEMA);
    int battery = args.at(0).toInt();
    m_batteryState = args.at(1).toInt();
    int timeToEmpty = args.at(2).toInt();
    int is_show = settings->get(GPM_SETTINGS_DISPLAY_LEFT_TIME).toInt();
    if (is_show) {
        powerTimeToEmpty->setText(
            QString(tr("Left %1h %2m")).arg((timeToEmpty) / 3600).arg(((timeToEmpty) % 3600) / 60));
    } else {
        powerTimeToEmpty->setText(QString(tr("Discharging")));
    }
    if (m_batteryState == 1 || m_batteryState == 5) {
        powerStateLabel->setText(tr("Charging"));

    } else if (m_batteryState == 4) {
        powerStateLabel->setText(tr("fully charged"));
    }
    batteryChange(m_batteryState);
    setSliderValue();
    percentageLabel->setText(QString("%1%").arg(battery));
}

void powerwindow::chargeNotify(bool state)
{
    //    qDebug() << "powerwindow::chargeNotify";
    //    if (!state) {
    //        QList<QVariant> args;
    //        args << tr("Power Manager") << ((unsigned int)0) << "ukui-power-manager" << tr("charge notification")
    //             << tr("battery is charging") << QStringList() << QVariantMap() << (int)-1;
    //        m_notifyInterface->callWithArgumentList(QDBus::AutoDetect, "Notify", args);
    //    } else {
    //        QList<QVariant> args;
    //        args << tr("Power Manager") << ((unsigned int)0) << "ukui-power-manager" << tr("discharged notification")
    //             << tr("battery is discharging") << QStringList() << QVariantMap() << (int)-1;
    //        m_notifyInterface->callWithArgumentList(QDBus::AutoDetect, "Notify", args);
    //    }
}

void powerwindow::full_charge_notify(DEV dev)
{
    //    qDebug() << "powerwindow::full_charge_notify";
    //    QList<QVariant> args;
    //    args << tr("Power Manager")
    //         << ((unsigned int)0)
    //         //    <<QString("battery-level-100-symbolic")
    //         << "ukui-power-manager" << tr("fullly charged notification") << tr("battery is fullly charged")
    //         << QStringList() << QVariantMap() << (int)-1;
    //    m_notifyInterface->callWithArgumentList(QDBus::AutoDetect, "Notify", args);
}

void powerwindow::lowBatteryNotify() {}

void powerwindow::criticalBatteryNotify() {}

void powerwindow::set_window_position()
{
    this->setWindowFlag(Qt::FramelessWindowHint);
    kdk::UkuiStyleHelper::self()->removeHeader(this);
    if (this->isVisible()) {
            this->show();
        } else {
            this->hide();
        }
    QRect rect;
    QDBusInterface iface("org.ukui.panel", "/panel/position", "org.ukui.panel", QDBusConnection::sessionBus());
    QDBusReply<QVariantList> reply = iface.call("GetPrimaryScreenGeometry");
    QVariantList position_list = reply.value();
    //    qDebug() << reply.value().at(2).toInt();
    switch (reply.value().at(4).toInt()) {
        case 1:
        rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN,
                     position_list.at(1).toInt() + MARGIN,
                     this->width(), this->height());
            break;
        case 2:
        rect = QRect(position_list.at(0).toInt() + MARGIN,
                     position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN,
                     this->width(), this->height());
            break;
        case 3:
        rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN,
                     position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN,
                     this->width(), this->height());
            break;
        default:
        rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN,
                     position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN,
                     this->width(), this->height());
            break;
    }
    kdk::WindowManager::setGeometry(this->windowHandle(), rect);
}

void powerwindow::watchTranspartency()
{
    const QByteArray transparency_id(TRANSPARENCY_SETTINGS);
    if (QGSettings::isSchemaInstalled(transparency_id)) {
        transparency_gsettings = new QGSettings(transparency_id);

        transparency = transparency_gsettings->get(TRANSPARENCY_KEY).toDouble() * 255;
        this->update();
        connect(transparency_gsettings, &QGSettings::changed, this, [=](const QString &key) {
            if (key == TRANSPARENCY_KEY) {
                transparency = transparency_gsettings->get(TRANSPARENCY_KEY).toDouble() * 255;
                this->update();
            }
        });
    } else {
        transparency = 0.75;
    }
}

void powerwindow::sliderValueChanged(int value)
{
    qDebug() << "slider value" << value << m_batteryState;
    if (1 == m_batteryState || 4 == m_batteryState || 5 == m_batteryState) {
        switch (value) {
            case 0:
                m_PowerManagerGsettings->set(POWER_POLICY_AC, EnergySaving);
                m_StateSlider->setToolTip(tr("Better endurance"));
                break;
            case 1:
                m_PowerManagerGsettings->set(POWER_POLICY_AC, Balance);
                m_StateSlider->setToolTip(tr("Better performance"));
                break;
            case 2:
                m_PowerManagerGsettings->set(POWER_POLICY_AC, Performance);
                m_StateSlider->setToolTip(tr("Best performance"));
                break;
            default:
                break;
        }
    } else {
        switch (value) {
            case 0:
                m_PowerManagerGsettings->set(POWER_POLICY_BATTERY, EnergySaving);
                m_StateSlider->setToolTip(tr("Better endurance"));
                break;
            case 1:
                m_PowerManagerGsettings->set(POWER_POLICY_BATTERY, Balance);
                m_StateSlider->setToolTip(tr("Better performance"));
                break;
            case 2:
                m_PowerManagerGsettings->set(POWER_POLICY_BATTERY, Performance);
                m_StateSlider->setToolTip(tr("Best performance"));
                break;
            default:
                break;
        }
    }
}

void powerwindow::setSliderValue()
{
    int policy = -1;
    if (1 == m_batteryState || 4 == m_batteryState || 5 == m_batteryState) {
        policy = m_PowerManagerGsettings->get(POWER_POLICY_AC).toInt();
    } else {
        policy = m_PowerManagerGsettings->get(POWER_POLICY_BATTERY).toInt();
    }
    qDebug() << "powerwindow::setSliderValue   m_batteryState ; policy is :" << m_batteryState << policy;
    switch (policy) {
        case Performance:
            m_StateSlider->setValue(2);
            m_StateSlider->setToolTip(tr("Best performance"));
            break;
        case Balance:
            m_StateSlider->setValue(1);
            m_StateSlider->setToolTip(tr("Better performance"));
            break;
        case EnergySaving:
            m_StateSlider->setValue(0);
            m_StateSlider->setToolTip(tr("Better endurance"));
            break;
        default:
            break;
    }
}

void powerwindow::paintEvent(QPaintEvent *e)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    p.setPen(Qt::NoPen);
    QColor color = palette().color(QPalette::Base);
    color.setAlpha(transparency);
    QBrush brush = QBrush(color);
    p.setBrush(brush);

    p.setRenderHint(QPainter::Antialiasing);
    p.drawRect(opt.rect);
}

bool powerwindow::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == this) {
        if (event->type() == QEvent::WindowDeactivate) {
            hide();
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}
